package com.app.framework.config;

import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.app.framework.annotations.ServiceClientVisible;
import com.app.framework.exception.ConfigException;
import com.app.framework.service.GameService;

public abstract class AbstractConfigLoader<T,E> implements ConfigLoader<T,E>{
	protected String fileName;
	private  Map<String,GameConfig<E>> configs=new HashMap<String,GameConfig<E>>();//key:xml中定义的id 
	public AbstractConfigLoader(String fileName) {
		this.fileName=fileName;
		try {
			load();
		} catch (Exception e) {
			e.printStackTrace();
			throw new ConfigException(e);
		}
	}
	@SuppressWarnings("unchecked")
	public void init(Class<T> clz) throws Exception {
		InputStream is;
		if(fileName.equals("prop.xml")) {
			is = new FileInputStream(System.getProperty("user.dir")+"/"+fileName);
		}
		else {
			is =this.getClass().getResourceAsStream("/config/"+fileName);
		}
		DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
		DocumentBuilder builder=factory.newDocumentBuilder();
		Document document=builder.parse(is);
		Element rootElement=document.getDocumentElement();
		NodeList elementList=rootElement.getChildNodes();
		GameConfig<E> model=null;
		for(int i=0;i<elementList.getLength();i++) {
			Node curNode=elementList.item(i);
			if(curNode.getNodeType() == Node.ELEMENT_NODE) {
				NamedNodeMap nodeMap=curNode.getAttributes();
				if(nodeMap!=null) {
					model=(GameConfig<E>) clz.newInstance();
					String id = nodeMap.getNamedItem("id").getNodeValue().trim();
					String value = nodeMap.getNamedItem("value").getNodeValue().trim();
					model.setId(id);
					model.setValue(value);
					configs.put(model.getId(), model);
				}
			}
		}
	}
	
	protected static Map<String,Method> loadClassMethods(Class<?> clz) {
		Class<?> surperclass=clz;
		Map<String,Method> map = new HashMap<String,Method>();

		if(GameService.class.isAssignableFrom(clz)) {
			while(surperclass != Object.class) {
				for(Method m : surperclass.getDeclaredMethods()) {
					if(m.isAnnotationPresent(ServiceClientVisible.class)) {
						m.setAccessible(true);
						if(!map.containsKey(m.getName())) {
							map.put(m.getName(), m);
						}
					}
				}
				surperclass=surperclass.getSuperclass();
			}
		}
		else {
			while(surperclass != Object.class) {
				for(Method m : surperclass.getDeclaredMethods()) {
					if(Modifier.isPublic(m.getModifiers()) && !Modifier.isFinal(m.getModifiers()) && !Modifier.isStatic(m.getModifiers())) {
						m.setAccessible(true);
						if(!map.containsKey(m.getName())) {
							map.put(m.getName(), m);
						}
					}
				}
				surperclass=surperclass.getSuperclass();
			}
		}
		return map;
	}
	
	@Override
	public Map<String, GameConfig<E>> getConfigs() {
		return configs;
	}
	
	@Override
	public GameConfig<E> getConfig(String name) {
		return configs.get(name);
	}
}
